package com.binc.testspring.study.design.iterator;

import com.google.common.collect.Lists;
import lombok.Data;
import lombok.ToString;

import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.function.Consumer;

/**
 * FileName: TestIterator_binc  测试迭代器模式   可移植版
 *
 *  讲解：
 *      我们有一个 书 类； 让后有一个书架类 bookshelf   ；书架相当于一个容器；里边有很多的书；正常来说我们需要遍历书架的书的话，我们需要取得书架对象，
 *      然后通过书架对象获取书的集合，让后遍历书的集合就行了； 或者在书架类内写一个遍历的方法；
 *      这个时候考虑这么一个场景，我们书的集合用的是List集合，那我们变了的话就要用 foreahc  fori等方式，不停的get；如果书的集合是数组呢；那我们无论是自己通过书
 *      架对象获得集合然后遍历还是书架类内写个遍历的方法；那这个实现明显跟list集合就不一样了；为了适应这样的场景，我们采用迭代器模式；我们像遍历书架内书的集合的话，
 *      我们去获取书架自己的迭代器，然后用这个迭代器去实现遍历；
 *
 *  为什么要在集合之外引入Iterator角色？
 *      引入Iterator后可以将遍历与实现分离开来
 *      这里使用了Iterator的hasNext方法和next方法，并没有调用BookShelf的方法。也就是说，这里的while循环并不依赖于BookShelf的实现
 *
 * Autho: binC
 * Date:  2022/4/1 11:14
 */
public class TestIterator_binc {

    public static void main(String[] args) {
        Book yuwen = new Book("语文",11);
        Book yingyu = new Book("英语",112);
        Book shuxue = new Book("数学",211);

        List<Book> list = Lists.newArrayList(yuwen,shuxue,yingyu);
        Vector vector = new Vector();
        vector.add(yuwen);
        vector.add(shuxue);
        vector.add(yingyu);

        BookShelf bs1 = new BookShelf(vector);
        BookShelf bs2 = new BookShelf(list);

        Iterator iterator = bs1.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        Iterator iterator1 = bs2.iterator2();
        while (iterator1.hasNext()) {
            System.out.println(iterator1.next());
        }

    }


}

//1 定义一个书架类  这是一个很纯粹的类，关于遍历的东西都不写到这里，给他准备一个类（用于书架中书的遍历）MyIteratro
class  BookShelf{
    private Vector<Book> books_vector  = new Vector<>();
    private List<Book>  bookList ;

    public BookShelf(Vector<Book> books_vector) {
        this.books_vector = books_vector;
    }

    public BookShelf(List<Book> books_array) {
        this.bookList = books_array;
    }

    void addBook(Book book){
        this.books_vector.add(book);
    }
    void addBookArray(Book book){
        this.bookList.add(book);
    }
    ///////////////


    Iterator iterator(){
        return new BookShelfIterator_vector(this.books_vector);
    }

    Iterator iterator2(){
        return new BookShelfIterator_array(this.bookList);
    }


}

// 2 定义一个书的类
@Data
@ToString
class Book{
    String name;
    int price;

    public Book(String name, int price) {
        this.name = name;
        this.price = price;
    }
}

// 3 定一个 单独用于书架中书的遍历的的一个类    实现jdk的Iterator有点坏处；就是这个接口的方法有点多，我们实际上只想要两个方法；  这个时候感觉还是自己定义一个 只有两个方法的MyIterator有优势了；
// 我们只重写 hasNext 和 next 两个方法；
class BookShelfIterator_vector implements Iterator{

    private Vector vector = new Vector();
    private int cursor = 0 ;// 定义一个游标

    public BookShelfIterator_vector(Vector vector) {
        this.vector = vector;
    }

    @Override
    public boolean hasNext() {
        if (this.cursor >= vector.size() ) {
            return false;
        }else {
            return true;
        }
    }


    @Override
    public Object next() {
        Object result = null;
        if (this.hasNext()) {
            result = this.vector.get(this.cursor++);
        } else {
            result = null;
        }
        return result;
    }
}
// 3-2 定一个 单独用于书架中书的遍历的的一个类    实现jdk的Iterator有点坏处；就是这个接口的方法有点多，我们实际上只想要两个方法；  这个时候感觉还是自己定义一个 只有两个方法的MyIterator有优势了；
// 我们只重写 hasNext 和 next 两个方法；
class BookShelfIterator_array implements Iterator {

    private List<Book> vector;
    private int cursor = 0;// 定义一个游标

    public BookShelfIterator_array(List<Book> vector) {
        this.vector = vector;
    }

    @Override
    public boolean hasNext() {
        if (this.cursor >= vector.size()) {
            return false;
        } else {
            return true;
        }
    }


    @Override
    public Object next() {
        Object result = null;
        if (this.hasNext()) {
            result = this.vector.get(this.cursor++);
        } else {
            result = null;
        }
        return result;
    }
}
